#include <os/list.h>
#include <os/mm.h>
#include <os/sched.h>
#include <pgtable.h>
#include <os/string.h>
#include <assert.h>
#include <pgtable.h>
#include <type.h>
#define MAXPAGE 10000
ptr_t memCurr = FREEMEM;
//mem_avaliable_t mem_mangement[MAXPAGE]; //管理物理页，有两种状态MEM_FREE和MEM_USED。初始状态全部为free
static LIST_HEAD(freePageList);


uintptr_t allocPage()
{
    //find first free page from FREEMEM
    int i;
    for(i=0;i<MAXPAGE&&mem_mangement[i]==MEM_USED;i++)
 	  	;//找到第一个空闲页
 	if(i>=MAXPAGE){
 		prints("all memory is used\n\r");
 		return 0;
 	}
 	
 	mem_mangement[i]=MEM_USED;
 	//从MEMFREE偏移出物理地址
 	uintptr_t pa=0x51001000lu+i*PAGE_SIZE;
    for(i=0;i<512;i++)
        ((PTE*)pa2kva(pa))[i]=0;
 	return pa;//return physical address 栈底
}
void* kmalloc(size_t size)
{
    ptr_t ret = ROUND(memCurr, 4);
    memCurr = ret + size;
    return (void*)ret;
}

void freePage(ptr_t baseAddr,uintptr_t pet_entry){//baseaddr是栈顶的虚地址
	int i;
	if(baseAddr>>63){//内核
		i=(baseAddr-0xffffffc000000000lu-0x51001000lu)/PAGE_SIZE-1;
	}
	else{//用户
		
	}
	if(i<0||i>=MAXPAGE){
		prints("error!illegal address\n\r");
		return ;
	}
	mem_mangement[i]=MEM_FREE;
}
uintptr_t shm_page_get(int key)
{
    // TODO(c-core):
}

void shm_page_dt(uintptr_t addr)
{
    // TODO(c-core):
}

/* this is used for mapping kernel virtual address into user page table */
void share_pgtable(uintptr_t dest_pgdir, uintptr_t src_pgdir)
{
    // TODO:
}

/* allocate physical page for `va`, mapping it into `pgdir`,
   return the kernel virtual address for the page.
   */
uintptr_t alloc_page_helper(uintptr_t va, uintptr_t pgdir)
{
 //va是输入的虚拟地址，pgdir是对应页表的入口虚拟地址。alloc_page_helper要做的是给该虚拟地址分配一个物理地址并在页表完成映射
    PTE* pte_first_enrty=pgdir;
    PTE* pte_second_enrty,pte_third_enrty;
    uintptr_t first_index=((va>>30)) & ~((~0)<< 9);
    uintptr_t second_index=((va)>>21) & ~((~0)<< 9);
    uintptr_t third_index=((va)>>12)& ~((~0)<< 9);
    if(pte_first_enrty[first_index]==0){//如果二级页表不存在则分配一个
    	((PTE*)pte_first_enrty)[first_index]=(allocPage()>>12)<<10|0x1;
    }
    pte_second_enrty=pa2kva((pte_first_enrty[first_index]>>10)<<12);
    if(pte_second_enrty[second_index]==0){//如果三级页表不存在则分配一个
    	((PTE*)pte_second_enrty)[second_index]=(allocPage()>>12)<<10|0x1;
    }
    pte_third_enrty=pa2kva((pte_second_enrty[second_index]>>10)<<12);
    uintptr_t physical_address=allocPage();
    uint64_t flag = _PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_USER;
    ((PTE*)pte_third_enrty)[third_index]=(flag|((physical_address>>12)<<10));
    return pa2kva(physical_address);
}